<template>
  <div class="absolute-full bg-black">
    <q-img class="absolute-full" src="bg.jpg" />
    <audio ref="winSnd" src="win.mp3" preload />
    <audio ref="tickSnd" src="tick.mp3" preload />

    <div class="_board absolute-center column">
      <div class="text-center text-red text-h5">准点击中 {{ hitTime }} 秒！</div>
      <q-space />
      <div class="_time text-center">
        <span :style="{ opacity: stopTime || goneTime < hideTime ? 1 : 0 }">{{ showTime.substr(0, showTime.length - 2) }}</span>
        <span>{{ showTime.substr(showTime.length - 2) }}</span>
      </div>
      <q-space />
      <div class="column q-pt-xl">
        <q-btn glossy push rounded color="blue" size="xl" @click="start" v-if="!refreshTime"><b>开 始</b></q-btn>
        <q-btn glossy push rounded color="red" size="xl" @click="stop" v-else><b>停 止</b></q-btn>
      </div>
    </div>

    <transition name="win">
      <div class="_win absolute-top full-width text-center" v-if="showWin">
        <div class="_wintext text-bold">
          {{ showWin }}
        </div>
      </div>
    </transition>
  </div>
</template>

<script>
// 【主视图区】
import { mapState } from 'vuex'
import key from 'keymaster'

export default {
  data: () => ({
    startTime: 0, // 开始时间
    stopTime: 0, // 停止时间
    refreshTime: 0 // 刷新时间
  }),

  computed: {
    ...mapState('main', ['maximized', 'hitTime', 'hideTime', 'winHints']),

    // 已经过的时间
    goneTime() {
      return this.refreshTime || this.stopTime ? ((this.stopTime || Date.now()) - this.startTime) / 1000 : 0
    },

    // 显示时间
    showTime() {
      return this.goneTime.toFixed(3)
    },

    // 胜利偏差列表（取绝对值）
    winOffsets() {
      return Object.keys(this.winHints).map(Math.abs).sort()
    },

    // 显示胜利信息
    showWin() {
      if (this.refreshTime || !this.startTime) return ''
      const diff = this.goneTime - this.hitTime
      for (const offset of this.winOffsets) {
        if (Math.abs(diff) > offset) continue
        if (diff < 0 && '-' + offset in this.winHints) {
          return this.winHints['-' + offset]
        } else if (diff > 0 && '+' + offset in this.winHints) {
          return this.winHints['+' + offset]
        } else if (offset in this.winHints) {
          return this.winHints[offset]
        }
      }
      return ''
    }
  },

  methods: {
    start() {
      this.startTime = Date.now()
      this.stopTime = 0
      this.refreshTime = 1

      // 开启每帧刷新
      const render = () => {
        if (!this.refreshTime) return
        this.refreshTime++
        window.requestAnimationFrame(render)
      }
      render()

      // 播放滴答音效
      this.$refs.winSnd.pause()
      this.$refs.tickSnd.currentTime = 0
      setTimeout(() => this.$refs.tickSnd.play(), 650)
    },

    stop() {
      this.stopTime = Date.now()
      this.refreshTime = 0

      // 若有奖励则播放胜利音效
      this.$refs.tickSnd.pause()
      if (this.showWin.includes('奖励')) {
        this.$refs.winSnd.currentTime = 0
        this.$refs.winSnd.play()
      }
    }
  },

  mounted() {
    if (process.env.DEBUGGING) {
      window.$m = this
    }

    // 绑定快捷键
    key.setScope('main')
    key('space', 'main', () => {
      this.refreshTime ? this.stop() : this.start()
      return false
    })
    if (process.env.MODE === 'electron') {
      key('esc', 'main', () => {
        if (this.maximized || this.$q.fullscreen.isActive) {
          this.$winCall('unmaximize')
        }
        return false
      })
    }
  }
}
</script>

<style lang="scss" scoped>
._board {
  width: 200px;
  height: 400px;
}
._time {
  font-family: Arial Black;
  color: #ffee55;
  transform: scale(16);
  filter: drop-shadow(#0009 1px 1px 1px);
}
._win {
  background-color: #0006;
  backdrop-filter: blur(20px);
}
._wintext {
  font-size: 100px;
  line-height: 2;
  color: #ff2211;
  filter: drop-shadow(#fff 2px 2px 2px);
}
.win-enter {
  opacity: 0.5;
  transform: scale(0.7);
}
.win-enter-active {
  transition: all 0.2s;
}
</style>
